package com.hejia.alauda.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;

import com.hejia.alauda.entity.PopularizeVisitHourStats;
import com.hejia.alauda.entity.example.PopularizeVisitHourStatsExample;
import com.hejia.alauda.persistence.mybatis.PopularizeVisitHourStatsMapper;
import com.hejia.alauda.utils.Pager;
import com.mongodb.AggregationOptions;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.Cursor;
import com.mongodb.DBObject;

@Service
public class PopularizeVisitHourStatsServiceImpl implements PopularizeVisitHourStatsService {

	private static final Log Logger = LogFactory.getLog(PopularizeVisitHourStatsServiceImpl.class);

	@Resource
	private MongoTemplate mongoTemplate;

	@Resource
	private PopularizeVisitHourStatsMapper popularizeVisitHourStatsMapper;

	@Override
	public List<LocalDate> findVisitDates() {

		// 解决timezone 8小时时差
		BasicDBList dbList = new BasicDBList();
		dbList.add("$createDate");
		dbList.add(28800000);

		// 按小时分组
		DBObject hourGroupFields = new BasicDBObject("year", new BasicDBObject("$year", new BasicDBObject("$add", dbList)));
		hourGroupFields.put("month", new BasicDBObject("$month", new BasicDBObject("$add", dbList)));
		hourGroupFields.put("day", new BasicDBObject("$dayOfMonth", new BasicDBObject("$add", dbList)));
		DBObject hourGroupIdField = new BasicDBObject("_id", hourGroupFields);
		DBObject hourGroup = new BasicDBObject("$group", hourGroupIdField);

		DBObject sortGroupFields = new BasicDBObject("_id.year", 1);
		sortGroupFields.put("_id.month", 1);
		sortGroupFields.put("_id.day", 1);
		DBObject sort = new BasicDBObject("$sort", sortGroupFields);

		List<DBObject> pipeline = Arrays.asList(hourGroup, sort);

		AggregationOptions options = AggregationOptions.builder().batchSize(100).outputMode(AggregationOptions.OutputMode.CURSOR).allowDiskUse(true).build();

		Cursor cursor = this.mongoTemplate.getCollection("popularizeVisit").aggregate(pipeline, options);

		List<LocalDate> dates = new ArrayList<>();
		while (cursor.hasNext()) {
			DBObject value = (DBObject) cursor.next().get("_id");
			dates.add(new LocalDate(
					Integer.parseInt(value.get("year").toString()), 
					Integer.parseInt(value.get("month").toString()), 
					Integer.parseInt(value.get("day").toString())));
		}

		return dates;
	}

	@Override
	public void statsVisitIPByDate(LocalDate date) {

		// 解决timezone 8小时时差
		BasicDBList dbList = new BasicDBList();
		dbList.add("$createDate");
		dbList.add(28800000);

		// 过滤指定日期数据
		Date startDate = date.toDate();
		Date endDate = date.plusDays(1).toDate();
		DBObject createDateCondition = new BasicDBObject("$gte", startDate);
		createDateCondition.put("$lt", endDate);
		DBObject matchCondition = new BasicDBObject("createDate", createDateCondition);
		DBObject match = new BasicDBObject("$match", matchCondition);

		// 按天去重相同IP数据
		DBObject dayGroupFields = new BasicDBObject("popularizeId", "$popularizeId");
		dayGroupFields.put("visitorIP", "$visitorIP");
		dayGroupFields.put("year", new BasicDBObject("$year", new BasicDBObject("$add", dbList)));
		dayGroupFields.put("month", new BasicDBObject("$month", new BasicDBObject("$add", dbList)));
		dayGroupFields.put("day", new BasicDBObject("$dayOfMonth", new BasicDBObject("$add", dbList)));

		DBObject dayGroupIdField = new BasicDBObject("_id", dayGroupFields);
		dayGroupIdField.put("createDate", new BasicDBObject("$first", "$createDate"));
		DBObject dayGroup = new BasicDBObject("$group", dayGroupIdField);

		// 按小时分组统计
		DBObject hourGroupFields = new BasicDBObject("popularizeId", "$_id.popularizeId");
		hourGroupFields.put("year", new BasicDBObject("$year", new BasicDBObject("$add", dbList)));
		hourGroupFields.put("month", new BasicDBObject("$month", new BasicDBObject("$add", dbList)));
		hourGroupFields.put("day", new BasicDBObject("$dayOfMonth", new BasicDBObject("$add", dbList)));
		hourGroupFields.put("hour", new BasicDBObject("$hour", new BasicDBObject("$add", dbList)));
		DBObject hourGroupIdField = new BasicDBObject("_id", hourGroupFields);
		hourGroupIdField.put("count", new BasicDBObject("$sum", 1));
		DBObject hourGroup = new BasicDBObject("$group", hourGroupIdField);

		List<DBObject> pipeline = Arrays.asList(match, dayGroup, hourGroup);

		AggregationOptions options = AggregationOptions.builder().batchSize(100).outputMode(AggregationOptions.OutputMode.CURSOR).allowDiskUse(true).build();

		Cursor cursor = this.mongoTemplate.getCollection("popularizeVisit").aggregate(pipeline, options);

		while (cursor.hasNext()) {
			DBObject value = cursor.next();
			DBObject id = (DBObject) value.get("_id");
			Long popularizeId = Long.parseLong(id.get("popularizeId").toString());
			Integer year = Integer.parseInt(id.get("year").toString());
			Integer month = Integer.parseInt(id.get("month").toString());
			Integer day = Integer.parseInt(id.get("day").toString());
			Integer hour = Integer.parseInt(id.get("hour").toString());
			Long count = Long.parseLong(value.get("count").toString());
			addOrUpdateVisitHourStats(popularizeId, year, month, day, hour, count);
		}
	}

	/**
	 * 添加访问汇总统计，已添加则更新
	 * @param popularizeId
	 * @param year
	 * @param month
	 * @param day
	 * @param hour
	 * @param count
	 */
	private void addOrUpdateVisitHourStats(Long popularizeId, Integer year, Integer month, Integer day, Integer hour, Long count) {

		Pager<PopularizeVisitHourStats> pager = new Pager<>();
		pager.setPageSize(1);
		
		DateTime statsHour = new DateTime(year, month, day, hour, 0);

		PopularizeVisitHourStatsExample example = new PopularizeVisitHourStatsExample();
		example.appendCriterion("popularizeId =", popularizeId);
		example.appendCriterion("statsHour =", statsHour.toDate());

		List<PopularizeVisitHourStats> visitHoures = popularizeVisitHourStatsMapper.selectByExample(example, pager);
		PopularizeVisitHourStats stats;
		if (visitHoures.size() < 1) {
			stats = new PopularizeVisitHourStats();
			stats.setPopularizeId(popularizeId);
			stats.setStatsHour(statsHour.toDate());
			stats.setVisitIPCount(count);
			stats.setCreateDate(new Date());
			stats.setModifyDate(new Date());
			this.popularizeVisitHourStatsMapper.insert(stats);
		} else {
			stats = visitHoures.get(0);
			stats.setVisitIPCount(count);
			stats.setModifyDate(new Date());
			this.popularizeVisitHourStatsMapper.updateByPrimaryKey(stats);
		}
	}

}
